/*
 * @Author: xiehangyun
 * @Date: 2025-02-20 10:10:37
 * @Last Modified by: xiehangyun
 * @Last Modified time: 2025-02-20 17:20:36
 */

import FabricImage from '@/myFabric/FabricImage';
import { fabric } from 'fabric';
import { ICanvasOptions } from 'fabric/fabric-impl';
import FabcriClippingRect from './FabcriClippingRect';
import { clamp } from 'lodash';
import utils from '@/utils/utils';

// 使用fabric实现裁剪
class FabricCropping extends fabric.Canvas {
  constructor(
    element: HTMLCanvasElement | string | null = FabricCropping.createCanvas(),
    options?: ICanvasOptions,
  ) {
    super(element, options);
    this.setActiveObject(this.clippingRect);

    this.on('before:render', (e) => {
      const objs = this.getObjects();
      var canvasWidth = this.width!;
      var canvasHeight = this.height!;
      for (let obj of objs) {
        // 获取对象的边界框
        var boundingRect = obj.getBoundingRect();

        obj.scaleX = clamp(obj.scaleX!, 0.1, 1);
        obj.scaleY = clamp(obj.scaleY!, 0.1, 1);

        obj.left = clamp(
          obj.left!,
          (canvasWidth - this.bgWidth) / 2,
          (canvasWidth + this.bgWidth) / 2 - boundingRect.width,
        );
        obj.top = clamp(
          obj.top!,
          (canvasHeight - this.bgHeight) / 2,
          (canvasHeight + this.bgHeight) / 2 - boundingRect.height,
        );

        // 更新对象坐标以实时生效
        obj.setCoords();

      }
    });
  }

  // 创建canvas
  static createCanvas() {
    return document.createElement('canvas');
  }

  // 设置容器
  setContainer(div: HTMLDivElement | null) {
    if (div) {
      div.style.overflow = 'hidden';
      div.innerHTML = '';
      div.append(this.getElement());
      div.append(this.getSelectionElement());
    }
  }

  // 背景的宽高值, 裁剪框需要限定在这个范围内
  bgWidth = 500;
  bgHeight = 500;

  // 设置背景图片
  setBackgroundImage(url: string) {
    var img = fabric.util.createImage();
    img.onload = () => {
      this.bgWidth = img.width;
      this.bgHeight = img.height;
      this.clippingRect.set({
        width: this.bgWidth,
        height: this.bgHeight,
        left: (500 - this.bgWidth) / 2,
        top: (500 - this.bgHeight) / 2,
        scaleX: 1,
        scaleY: 1,
      });
      this.setDimensions({ width: 500, height: 500 });
      this.setActiveObject(this.clippingRect);
      super.setBackgroundImage(url, () => {
        (this.backgroundImage as FabricImage).set({ left: 250, top: 250 });
        this.renderAll();
      });
    };
    img.src = url;
    return this;
  }

  //裁剪矩形
  clippingRect = (() => {
    const clippingRect = new FabcriClippingRect({
      width: 300,
      height: 300,
      left: 250,
      top: 250,
    });
    this.add(clippingRect);
    return clippingRect;
  })();

  // 创建 Canvas 对象
  tempCanvas = document.createElement('canvas');

  // 裁剪后的文件
  async cropImage(): Promise<File> {

    var canvasWidth = this.width!;
    var canvasHeight = this.height!;

    return new Promise<File>((resolve, reject) => {
      // 加载图片
      const img = new Image();
      img.crossOrigin = 'anonymous'; // 解决跨域问题

      img.onload = () => {
        // 创建 Canvas 对象
        const ctx = this.tempCanvas.getContext('2d');

        if (!ctx) {
          reject(new Error('无法获取 Canvas 上下文'));
          return;
        }

        //计算缩放值
        const scale = Math.max(img.naturalWidth / this.bgWidth, img.naturalHeight / this.bgHeight);

        //计算裁剪参数
        var boundingRect = this.clippingRect.getBoundingRect();

        boundingRect.left -= (canvasWidth - this.bgWidth) / 2;
        boundingRect.top -= (canvasHeight - this.bgHeight) / 2;

        boundingRect.left *= scale;
        boundingRect.top *= scale;
        boundingRect.width *= scale;
        boundingRect.height *= scale;

        // 设置 Canvas 的宽度和高度为裁剪区域的大小
        this.tempCanvas.width = boundingRect.width;
        this.tempCanvas.height = boundingRect.height;

        // 将图片绘制到 Canvas 上，并根据裁剪参数进行裁剪
        ctx.drawImage(
          img, boundingRect.left, boundingRect.top, boundingRect.width, boundingRect.height,
          0, 0, boundingRect.width, boundingRect.height,
        );

        // 从 Canvas 中提取图像数据
        this.tempCanvas.toBlob((blob) => {
          if (blob) {
            // 将 Blob 转换为 File 对象
            const file = new File([blob], 'croppedImage.png', { type: blob.type });
            resolve(file);
          } else {
            reject(new Error('无法提取图像数据'));
          }
        }, 'image/png');
      };

      img.onerror = (error) => {
        console.error('图片加载失败:', error);
        reject(new Error('图片加载失败'));
      };

      img.src = utils.ossSuffix((this.backgroundImage as FabricImage).getSrc());
    });
  }
}

// 裁剪的实例对象
const fabricCropping = new FabricCropping();

export default fabricCropping;
